package com.black.knight.chess.components;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.RemoteViews.RemoteView;
import android.widget.TextView;

import com.black.knight.chess.R;
import com.black.knight.chess.SahMatActivity;
import com.black.knight.chess.domain.Player;
import com.black.knight.chess.model.SahModel;

@RemoteView
public class ChessClock extends View {
    private Date mCalendar;

    private Drawable mHourHand;
    private Drawable mMinuteHand;
    private Drawable mSecondHand;
    private Drawable mDial;
   
    private int mDialWidth;
    private int mDialHeight;
    
    private float mMinutes;
    private float mHour;
    private float mSeconds;
    private boolean mChanged;
    
    private SahMatActivity mContext;
    
    private TextView textView;
    
    private Player player;
    
    private long startTime;
    
    public static long GAME_DURATION = 1000 * 60 * 15;
    
    private DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
    
    public boolean ismChanged() {
		return mChanged;
	}

	public void setmChanged(boolean mChanged) {
		this.mChanged = mChanged;
		
		if(mChanged) {
			mContext.runOnUiThread(new Runnable() {
				@Override
				public void run() {
					invalidate();
					if(textView != null) {
						textView.setText(player.getName() + (SahModel.getInstance().getGame().isPlayOnClock() ? ("\n" + getFormatedTime()) : ""));
					}
					
			        if(isExpired()) {
			        	stop();
			        	SahModel.getInstance().getGame().timeOut(player);
			        }
				}
			});
		}
	}

	private Timer timer;

    public ChessClock(SahMatActivity context) {
        this(context, null);
        this.mContext = context;
    }
    
    public void start() {
    	stop();
    	
    	timer = new Timer();
    	timer.schedule(new TimerTask() {
			@Override
			public void run() {
				mCalendar.setTime(mCalendar.getTime() + 1000);
		        
				int hour = mCalendar.getHours();
		        int minute = mCalendar.getMinutes();
		        int second = mCalendar.getSeconds();

		        mMinutes = minute + second / 60.0f;
		        mHour = hour + mMinutes / 60.0f;
		        mSeconds = second;
		        setmChanged(true);
			}
		}, 1000, 1000);    	
    }
    
    public void reset() {
    	stop();
    	mCalendar = new Date(0);
        mCalendar.setHours(0);
        
        startTime = mCalendar.getTime();
        
        setmChanged(true);
    }
    
    public void stop() {
    	if(timer != null) {
    		timer.cancel();
    		timer = null;
    	}
    }
    
    public String getFormatedTime() {
    	return String.valueOf(dateFormat.format(new Date(GAME_DURATION - elapsedTime() + (mCalendar.getTimezoneOffset() * 60000))));
    }
    
    public boolean isExpired() {
    	return elapsedTime() >= GAME_DURATION;
    }

    public ChessClock(SahMatActivity context, AttributeSet attrs) {
    	this(context, attrs, 0);
        this.mContext = context;
    }

    public ChessClock(SahMatActivity context, AttributeSet attrs,
                       int defStyle) {
        super(context, attrs, defStyle);
        this.mContext = context;
        Resources r = context.getResources();
        

        if (mDial == null) {
            mDial = r.getDrawable(R.drawable.clock_dial);
        }
                
        if (mHourHand == null) {
            mHourHand = r.getDrawable(R.drawable.clock_hand_hour);
        }

        if (mMinuteHand == null) {
            mMinuteHand = r.getDrawable(R.drawable.clock_hand_minute);
        }
        
        if (mSecondHand == null) {
        	mSecondHand = r.getDrawable(R.drawable.clock_hand_second);
        	mSecondHand.setColorFilter(context.getResources().getColor(R.color.red), Mode.SRC_IN);
        }

        mCalendar = new Date(0);
        mCalendar.setHours(0);
        
        startTime = mCalendar.getTime();

        mDialWidth = mDial.getIntrinsicWidth();
        mDialHeight = mDial.getIntrinsicHeight();
    }
    
    public long elapsedTime() {
    	return mCalendar.getTime() - startTime;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize =  MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize =  MeasureSpec.getSize(heightMeasureSpec);

        float hScale = 1.0f;
        float vScale = 1.0f;

        if (widthMode != MeasureSpec.UNSPECIFIED && widthSize < mDialWidth) {
            hScale = (float) widthSize / (float) mDialWidth;
        }

        if (heightMode != MeasureSpec.UNSPECIFIED && heightSize < mDialHeight) {
            vScale = (float )heightSize / (float) mDialHeight;
        }

        float scale = Math.min(hScale, vScale);

        setMeasuredDimension(resolveSize((int) (mDialWidth * scale), widthMeasureSpec),
                resolveSize((int) (mDialHeight * scale), heightMeasureSpec));
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        setmChanged(true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        boolean changed = ismChanged();
        if (changed) {
            setmChanged(false);
        }
        
        int availableWidth = getRight() - getLeft();
        int availableHeight = getBottom() - getTop();

        int x = availableWidth / 2;
        int y = availableHeight / 2;

        final Drawable dial = mDial;
        int w = dial.getIntrinsicWidth();
        int h = dial.getIntrinsicHeight();

        boolean scaled = false;

        if (availableWidth < w || availableHeight < h) {
            scaled = true;
            float scale = Math.min((float) availableWidth / (float) w,
                                   (float) availableHeight / (float) h);
            canvas.save();
            canvas.scale(scale, scale, x, y);
        }

        if (changed) {
            dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
        }
        dial.draw(canvas);

        canvas.save();
        canvas.rotate(mHour / 12.0f * 360.0f, x, y);
        final Drawable hourHand = mHourHand;
        if (changed) {
            w = hourHand.getIntrinsicWidth();
            h = hourHand.getIntrinsicHeight();
            hourHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
        }
        hourHand.draw(canvas);
        canvas.restore();

        canvas.save();
        canvas.rotate(mMinutes / 60.0f * 360.0f, x, y);

        final Drawable minuteHand = mMinuteHand;
        if (changed) {
            w = minuteHand.getIntrinsicWidth();
            h = minuteHand.getIntrinsicHeight();
            minuteHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
        }
        minuteHand.draw(canvas);
        canvas.restore();
        
        canvas.save();
        canvas.rotate(mSeconds / 60.0f * 360.0f, x, y);

        final Drawable secondHand = mSecondHand;
        if (changed) {
            w = secondHand.getIntrinsicWidth();
            h = secondHand.getIntrinsicHeight();
            secondHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
        }
        secondHand.draw(canvas);
        canvas.restore();

        if (scaled) {
            canvas.restore();
        }
    }

	public TextView getTextView() {
		return textView;
	}

	public void setTextView(TextView textView) {
		this.textView = textView;
	}

	public Player getPlayer() {
		return player;
	}

	public void setPlayer(Player player) {
		this.player = player;
	}
}
